require "ParticleList.lua"
--require "UIScrollBar.lua"

LFET_POINT_INDEX_OF_LEFT_EYE = 45
RIGHT_POINT_INDEX_OF_RIGHT_EYE = 36
DURATION_PER_FRAME = 100.0
EMIT_COUNT_SCALE_FACTOR = 10

g_kuruFaceDetector = nil
g_kuruTouch = nil
g_kuruEngineInstance = nil
--g_gyroCameraNode = nil
g_lastEmitFrameIndex = 0
g_totalElapsedTime = 0.0
g_leftParticles = {}
g_rightParticles = {}


function initialize(scene)
  local cameraSnapshot = getSnapshot(scene)

  addNodeAndRelease(scene, KuruClearNode.create(Vector4.create(0.0, 0.0, 0.0, 0.0)))
  addNodeAndRelease(scene, KaleFaceSkinNode.create( KaleFaceSkinNodeBuilder.create():path(BASE_DIRECTORY .. "facemask.png"):skinType(KaleFaceSkinType.FACE_EX):build()))

  local faceMaskSnapshot = getSnapshot(scene)

  local passthroughNode = addNodeAndRelease(scene, getFragmentShader("passthrough.frag"))
  passthroughNode:setChannel0(cameraSnapshot:getSampler())
  init(scene)

  local leftNames = populateLeftParticleNames()
  local rightNames = populateRightParticleNames()

  setupParticles(leftNames, g_leftParticles)
  setupParticles(rightNames, g_rightParticles)

  buildParticles(scene)

  local displayNode = addNodeAndRelease(scene, getFragmentShader("display.frag"))

  displayNode:setChannel1(faceMaskSnapshot:getSampler())
  displayNode:setChannel2(cameraSnapshot:getSampler())
  --g_scrollBar = UIScrollBar:init(scene, 0.0)
end

function frameReady(scene, elapsedTime)
  --g_scrollBar:frameReady(scene, elapsedTime)

  local faceCnt = g_kuruFaceDetector:getFaceCount()

  g_totalElapsedTime = g_totalElapsedTime + elapsedTime

  if (faceCnt > 0) then
    local currentFrameIndex = math.floor(g_totalElapsedTime / DURATION_PER_FRAME)
   -- local emitIntervalFrameCount = math.floor((1.0 - g_scrollBar:getStrength()) * EMIT_COUNT_SCALE_FACTOR)
       local emitIntervalFrameCount = math.floor((1.0 - 0.35) * EMIT_COUNT_SCALE_FACTOR)

    if (g_lastEmitFrameIndex + emitIntervalFrameCount <= currentFrameIndex ) then
      g_lastEmitFrameIndex = currentFrameIndex

      local faceFeature = KaleFaceFeature.cast(g_kuruFaceDetector:getFace(0))
      local faceData = faceFeature:getFaceData()
      local topLeftPositionEyeBox = normalizeToZeroToOne(faceData:getUlseeVertexShape(LFET_POINT_INDEX_OF_LEFT_EYE))
      local topRightPositionEyeBox = normalizeToZeroToOne(faceData:getUlseeVertexShape(RIGHT_POINT_INDEX_OF_RIGHT_EYE))
      local aspectRatio = scene:getResolution().x / scene:getResolution().y
      local faceCos = math.cos(math.rad(faceData.relativeRoll))
      local faceSin = math.sin(math.rad(faceData.relativeRoll))
      local rightEyeX = faceCos * 0.16 - faceSin * (0.15 / aspectRatio) - 0.25
      local rightEyeY = faceSin * 0.16 + faceCos * (0.15 / aspectRatio) + 0.28
      local leftEyeX = -faceCos * 0.16 - faceSin * (0.15 / aspectRatio) + 0.25
      local leftEyeY = -faceSin * 0.16 + faceCos * (0.15 / aspectRatio) + 0.28
      local rightEyeGapY = faceCos * (0.1 / aspectRatio)
      local leftEyeGapY = faceCos * (0.1 / aspectRatio)

      emitOnPosition(topLeftPositionEyeBox.x + leftEyeX, topLeftPositionEyeBox.y + (leftEyeY * aspectRatio), leftEyeGapY, g_leftParticles)
      emitOnPosition(topRightPositionEyeBox.x + rightEyeX, topRightPositionEyeBox.y + (rightEyeY * aspectRatio), rightEyeGapY, g_rightParticles)
    end
  end

  g_gyroCameraNode:setRotationWithQuaternion(CameraConfig.instance():getGyroQuaternion())
end

function finalize(scene)
  g_kuruTouch:getTouchDownEvent():removeEventHandler(onTouchDown)
  g_kuruTouch:getTouchMoveEvent():removeEventHandler(onTouchMove)
  g_kuruTouch:getTouchUpEvent():removeEventHandler(onTouchUp)
end

--function onTouchDown(event)
--  g_scrollBar:onTouchDown(event)
--end

--function onTouchMove(event)
--  g_scrollBar:onTouchMove(event)
--end

--function onTouchUp(event)
--  g_scrollBar:onTouchUp(event)
--end

function getSnapshot(scene)
  local node = KuruSnapshotNode.create()

  scene:addNode(node)
  node:release()

  return node
end

function addNodeAndRelease(scene, node)
  scene:addNode(node)
  node:release()

  return node
end

function setupParticles(particleNames, particles)
  for i, name in ipairs(particleNames) do
    particle = KuruParticleNode.create(getFilePath(name))
    table.insert(particles, particle)
  end
end

function init(scene)
  g_kuruEngineInstance = KuruEngine.getInstance()
  g_kuruFaceDetector = KuruFaceDetectorExtension.cast(g_kuruEngineInstance:getExtension("KuruFaceDetector"))
  g_kuruTouch = KuruTouchExtension.cast(g_kuruEngineInstance:getExtension("KuruTouch"))
  g_kuruTouch:getTouchDownEvent():addEventHandler(onTouchDown)
  g_kuruTouch:getTouchMoveEvent():addEventHandler(onTouchMove)
  g_kuruTouch:getTouchUpEvent():addEventHandler(onTouchUp)
  --CAMERA NODE CREATE
  local gyroParentCameraNode = KuruCameraNode.create(45, 10, 10000)
  g_gyroCameraNode = KuruCameraNode.create(45, 10, 10000)

  gyroParentCameraNode:addChild(g_gyroCameraNode)

  scene:addNode(gyroParentCameraNode)
  gyroParentCameraNode:release()
  g_gyroCameraNode:release()
end

function normalizeToZeroToOne(minusOneToOneVec2)
  local normalizedX = (minusOneToOneVec2.x + 1.0) / 2.0
  local normalizedY = (minusOneToOneVec2.y + 1.0) / 2.0

  return Vector2.create(normalizedX, normalizedY)
end

function buildParticles(scene)
  addParticles(g_leftParticles)
  addParticles(g_rightParticles)

  local kuruCameraNode = KuruCameraNode.create(45, 10, 10000)
  scene:addNode(kuruCameraNode)
  kuruCameraNode:release()
  particleStopEmitOnce(0)
end

function addParticles(particles)
  for i, particle in ipairs(particles) do
    particle:setBillboard(true)
    particle:start()
    g_gyroCameraNode:addChild(particle)
    particle:release()
  end
end

function particleStartEmitOnce(count, particles)
  for i, particle in ipairs(particles) do
    particle:emitOnce(count)
    particle:start()
  end
end

function particleStopEmitOnce(count)
  for i, particle in ipairs(g_leftParticles) do
    particle:emitOnce(count)
    particle:stop()
  end

  for i, particle in ipairs(g_rightParticles) do
    particle:emitOnce(count)
    particle:stop()
  end
end

function emitOnPosition(posX, posY, posYGap, particles)
  local resolution = g_kuruEngineInstance:getResolution()

  camera = g_gyroCameraNode:getCamera()
  local distance = camera:getFitDistance(resolution.x);

  for i, particle in ipairs(particles) do
    local x = (1.0 - posX - 0.5)
    local y = (posY - 0.5)
    local transX = x * resolution.x
    local transY = (y + (i - 1) * posYGap) * resolution.y
    local vec3 = Vector3.create(transX, transY, distance)
    local emitter = ParticleEmitter.cast(particle:getParticleEmitter())
    emitter:setPosition(vec3, emitter:getPositionVariance());
  end

  particleStartEmitOnce(1, particles)
end

function getFilePath(fileName)
    return BASE_DIRECTORY .. fileName
end

function getFragmentShader(filePath)
  return KuruShaderFilterNode.createWithFragmentShaderFile(BASE_DIRECTORY .. filePath, true)
end
